package edu.gmu.atelier.generic;

import edu.gmu.atelier.Epsilon;
import java.util.ArrayList;
import java.util.List;

/**
 * Set of vectors with vector combination and scalar multiplication operations.
 * @author James H. Pope
 */
public class AbstractMatrix <T extends Vector> implements Matrix<T>
{
    private List<T> vectors = null; 
    
    public AbstractMatrix( T[] vs )
    {
        this.vectors = new ArrayList<T>();
        for (int i = 0; i < vs.length; i++)
        {
            this.vectors.add(vs[i]);
        }
    }
    
    public AbstractMatrix( List<T> vectors )
    {
        this.vectors = vectors;
    }
    
    public int getRows()
    {
        return this.vectors.get(0).getLength();
    }

    public int getCols()
    {
        return this.vectors.size();
    }
    
    public List<T> getVectors()
    {
        return this.vectors;
    }
    
    public double[][] getData()
    {
        double[][] data = new double[this.getRows()][this.getCols()];
        for (int i = 0; i < data.length; i++)
        {
            for (int j = 0; j < data.length; j++)
            {
                data[i][j] = this.vectors.get(j).getElement(i);
            }
        }
        return data;
    }

    public T mult(T x)
    {
        // Generic algorithm
        T b = (T)vectors.get(0).make();
        for (int i = 0; i < x.getLength(); i++)
        {
            b.multAdd(x.getElement(i), vectors.get(i));
        }
        return b;
    }

    public AbstractMatrix<T> mult( Matrix<T> b )
    {
        List<T> c = new ArrayList<T>();
        for (int j = 0; j < b.getCols(); j++)
        {
            T v = (T)b.getVector(j);
            c.add( this.mult(v) );
        }
        return new AbstractMatrix(c);
    }

    public void mult(double scalar)
    {
        for (int i = 0; i < vectors.size(); i++)
        {
            vectors.get(i).mult(scalar);
        }
    }

    public T getVector(int j)
    {
        return this.vectors.get(j);
    }

    public AbstractMatrix<T> transpose()
    {
        throw new UnsupportedOperationException("Not Supported");
    }

    public boolean similar( Object obj, Epsilon e )
    {
        if(obj == this)
        {
            return true;
        }
        
        if( (obj instanceof AbstractMatrix) == false )
        {
            return false;
        }
        
        AbstractMatrix o = (AbstractMatrix)obj;
        
        if( o.vectors.size() != this.vectors.size() )
        {
            return false;
        }
        
        for (int i = 0; i < this.vectors.size(); i++)
        {
            if( this.vectors.get(i).similar(o.vectors.get(i), e) == false )
            {
                return false;
            }
        }
        
        return true;
    }
    
    
    //------------------------------------------------------------------------//
    // Class instance methods
    //------------------------------------------------------------------------//
    public boolean equals( Object obj )
    {
        return this.similar(obj, null);
    }
    
    public String toString()
    {
//        StringBuilder buf = new StringBuilder("[");
//        for (int i = 0; i < vectors.size(); i++)
//        {
//            buf.append( "\nv"+i+"="+vectors.get(i));
//        }
//        buf.append("]");
//        return buf.toString();
        StringBuilder buf = new StringBuilder();
        for (int i = 0; i < vectors.size(); i++)
        {
            buf.append( "\n[");
            for (int j = 0; j < vectors.get(0).getLength(); j++)
            {
                buf.append(vectors.get(j).getElement(i));
                buf.append( "," );
            }
            buf.append( "]");
        }
        return buf.toString();
    }

}
